﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;
using System.Threading;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml;

namespace HSIA
{
    class SocketServer
    {
        public delegate void SetNotifyIconTip(string sTitle, string sText);
        public delegate void SetMonitor(string sIP, byte[] byteData, int iType);
        public SetNotifyIconTip setNotifyIconTip;
        public SetMonitor setMonitor;

        Hashtable htSocket_GPSClient = new Hashtable();
        Hashtable htSocket_PCClient = new Hashtable();
        Hashtable htRecedByte = new Hashtable();

        DataOrder ao;
        Socket sListener;

        int iRecMaxLen = 2048;
        int iRecTimeout = 5000;
        int iPort;
        string sServerIP;
        bool isConnect = false;

        public SocketServer(DataOrder pao)
        {
            ao = pao;
        }

        public void SetParam(string psServerIP, int piPort, int piReceiveTimeout)
        {
            sServerIP = psServerIP;
            iPort = piPort;
            iRecTimeout = piReceiveTimeout;
        }

        /// <summary>
        /// 启动监听
        /// </summary>
        public void CreateServer()
        {
            sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                sListener.Bind(new IPEndPoint(IPAddress.Parse(sServerIP), iPort));
                sListener.Listen(100);
                sListener.BeginAccept(new AsyncCallback(OnConnectRequest), sListener);
            }
            catch (Exception e)
            {
                string str = (PublicFunc.sLanguage == "CN") ? "监听错误!" : "Network port has been temporarily used!";
                MessageBox.Show(sServerIP + str + e.Message, "Warn!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
        }

        /// <summary>
        /// 异步接受客户端连接
        /// </summary>
        /// <param name="ar"></param>
        private void OnConnectRequest(IAsyncResult ar)
        {
            Socket listener = (Socket)ar.AsyncState;
            try
            {
                Socket sock = listener.EndAccept(ar);
                string sIP = "";
                GetIPFromSocket(sock, ref sIP);

                if (htSocket_GPSClient.ContainsKey(sIP))
                {
                    RemoveClient(sIP);
                }
                htSocket_GPSClient.Add(sIP, sock);

                listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);

                byte[] temp = new byte[iRecMaxLen];
                sock.BeginReceive(temp, 0, 0, SocketFlags.None, new AsyncCallback(OnReceiveData), sock);

                //isConnect = false;
                //for (int i = 0; i < 2; i++)
                //{
                //    if (isConnect) break;
                //    Thread.Sleep(500);
                //    byte[] byteHex = SendOrder(sIP, bConnect);
                //    Thread.Sleep(1000);
                //}
            }
            catch
            {
                //listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
            }
        }

        /// <summary>
        /// 获取客户端IP
        /// </summary>
        /// <param name="clientSock"></param>
        /// <param name="sIP"></param>
        private void GetIPFromSocket(Socket clientSock, ref string sIP)
        {
            try
            {
                IPEndPoint ip = clientSock.RemoteEndPoint as IPEndPoint;
                sIP = ip.Address.ToString() + "," + ip.Port.ToString();
            }
            catch
            {
                clientSock.Close();
                return;
            }
        }

        /// <summary>
        /// 异步接收数据
        /// </summary>
        /// <param name="iar"></param>
        private void OnReceiveData(IAsyncResult iar)
        {
            Socket sClient = (Socket)iar.AsyncState;
            if (sClient == null) return;
            string sIP = "";
            GetIPFromSocket(sClient, ref sIP);
            byte[] byteReceive = (byte[])htRecedByte[sIP];
            if (byteReceive == null)
            {
                byteReceive = new byte[4096];
                htRecedByte.Add(sIP, byteReceive);
                try
                {
                    if (!sClient.Connected)
                    {
                        RemoveClient(sIP);
                        return;
                    }
                    sClient.BeginReceive(byteReceive, 0, byteReceive.Length, SocketFlags.None, new AsyncCallback(OnReceiveData), sClient);
                }
                catch { }
                return;
            }

            int iRec = 0;
            string sTipText = "", sMsg = "";

            try
            {
                iRec = sClient.EndReceive(iar);
            }
            catch (Exception e)
            {
                sTipText = "[" + sIP + "]";
                sMsg = e.Message;
                RemoveClient(sIP);
                sClient.Close();
            }

            if (iRec > 0)
            {
                try
                {
                    byte[] byteData = new byte[iRec];
                    Buffer.BlockCopy(byteReceive, 0, byteData, 0, iRec);
                    //for (int i = 0; i < iRec; i++) byteReceive[i] = 0;
                    byteReceive.Initialize();
                    //if (receiveData != null) receiveData(byteData, sIP);
                    AmateBussiness.ToLog("DataHex " + DateTime.Now.ToString("yyyy-MM-dd"), PublicFunc.GetUniformDateString(DateTime.Now), byteData);
                    setMonitor(sIP, byteData, 1);

                    if (iRec >= 2)
                    {
                        string[] strs = ao.CollectData(sIP, byteData).Split(';');
                        if (strs.Length > 1)
                        {
                            sTipText = strs[0];
                            sMsg = strs[1];
                            if (sMsg.EndsWith("Error"))
                            {
                                AmateBussiness.ToLog("DataError", DateTime.Now.ToString(), sTipText + sMsg);
                            }
                        }
                    }
                    //else
                    //{
                    //    SendOrder(sIP, ao.NOT(byteData));
                    //}
                }
                catch (Exception e)
                {
                    sTipText = "Rec.(" + PublicFunc.GetTableCellValue(ao.dtReceiver, "Port", sIP, "KeyId") + ")";
                    sMsg = e.Message + "Error";
                    AmateBussiness.ToLog("AnalysisError", DateTime.Now.ToString(), sTipText + sMsg);
                }
                try
                {
                    sClient.BeginReceive(byteReceive, 0, byteReceive.Length, SocketFlags.None, new AsyncCallback(OnReceiveData), sClient);
                }
                catch (Exception e)
                {
                    sTipText = "Rec.(" + PublicFunc.GetTableCellValue(ao.dtReceiver, "Port", sIP, "KeyId") + ")";
                    sMsg = e.Message;
                    RemoveClient(sIP);
                    sClient.Close();
                }
            }
            if (sMsg != "") setNotifyIconTip("[" + sTipText + "]", sMsg);
            //else if (sClient.Available == 0)
            //{
            //    byte[] byteHex = SendOrder(sIP, new byte[] { 0x0A });
            //    if (sClient.Poll(10, SelectMode.SelectRead))
            //    {
            //        RemoveClient(sIP);
            //        sClient.Close();
            //        return;
            //    }
            //}
        }

        /// <summary>
        /// 移除连接
        /// </summary>
        /// <param name="sIP"></param>
        private void RemoveClient(string sIP)
        {
            lock (htSocket_GPSClient)
            {
                if (htSocket_GPSClient.ContainsKey(sIP))
                {
                    Socket clientOld = (Socket)htSocket_GPSClient[sIP];
                    clientOld.Close();
                    htSocket_GPSClient.Remove(sIP);
                }
                if (htRecedByte.ContainsKey(sIP)) htRecedByte.Remove(sIP);
            }
        }

        /// <summary>
        /// 向客户端发送数据
        /// </summary>
        /// <param name="sIP"></param>
        /// <param name="byteHex"></param>
        /// <returns></returns>
        public bool SendOrder(string sIP, byte[] byteHex)
        {
            bool b = false;
            if (byteHex == null || byteHex.Length == 0) return b;
            if (!htSocket_GPSClient.ContainsKey(sIP)) return b;

            //Thread.Sleep(500);

            Socket client = (Socket)htSocket_GPSClient[sIP];

            //if (!client.Connected)
            //{
            //    RemoveGPSClient(sIP);
            //    if (!htOrderByte.ContainsKey(sIP)) htOrderByte.Add(sIP, byteHex);
            //    return null;
            //}

            //NetworkStream ns = client.GetStream();
            try
            {
                client.Send(byteHex);
                //ns.Write(byteHex, 0, byteHex.Length);
                setMonitor(sIP, byteHex, 0);
                return true;
            }
            catch (Exception e)
            {
                RemoveClient(sIP);
                setNotifyIconTip(sIP, e.Message);
                return b;
            }
        }
        
        /// <summary>
        /// 停止监听
        /// </summary>
        public void StopListener()
        {
            foreach (DictionaryEntry de in htSocket_GPSClient)
            {
                ((Socket)de.Value).Close();
            }
            htSocket_GPSClient.Clear();
            htSocket_PCClient.Clear();
            sListener.Close();
        }

        public void UDPClientSend(byte[] netInfo)
        {
            UdpClient uc = new UdpClient();
            IPEndPoint IPendp = new IPEndPoint(IPAddress.Broadcast, 8800);
            IAsyncResult oAsyncResult = uc.Client.BeginConnect(IPAddress.Broadcast, 8800, null, null);
            oAsyncResult.AsyncWaitHandle.WaitOne(100, true);//1000为超时时间
            uc.BeginSend(netInfo, netInfo.Length, null, null);
        }

        public void TCPClientSend(byte[] netInfo)
        {
            foreach (DictionaryEntry de in htSocket_PCClient)
            {
                string sIP = de.Key.ToString();
                SendOrder(sIP, netInfo);
            }
        }

    } 

}
